using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Windows.Forms;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
using System.Threading;
using System.ComponentModel;
using EntLibContrib.PolicyInjection.CallHandlers;

namespace EntLibContrib.PolicyInjection.Tests
{
    [TestClass]
    public class ThreadSafeCallHandlerFixture
    {
        [TestMethod, DeploymentItem("ThreadSafeCallHandler.config")]
        public void Target_With_Configuration()
        {
            IConfigurationSource configurationSource = new FileConfigurationSource("ThreadSafeCallHandler.config");

            ThreadSafeFoo foo = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Create<ThreadSafeFoo>(configurationSource);

            AutoResetEvent thread1Enters = new AutoResetEvent(false);
            AutoResetEvent thread2Enters = new AutoResetEvent(false);
            AutoResetEvent thread1Finishes = new AutoResetEvent(false);
            AutoResetEvent thread2Finishes = new AutoResetEvent(false);
            
            ThreadPool.QueueUserWorkItem(delegate(object notUsed)
            {
                foo.Do(thread1Enters, thread1Finishes);
            });

            ThreadPool.QueueUserWorkItem(delegate(object notUsed)
            {
                foo.Do(thread2Enters, thread2Finishes);
            });

            Thread.Sleep(100); // Give time to both theads to try to enter.

            bool thread1Entered = thread1Enters.WaitOne(0, false);
            bool thread2Entered = thread2Enters.WaitOne(0, false);

            Assert.IsFalse(thread1Entered && thread2Entered, "Both theads entered the lock for the same SyncRoot");
        }

        [TestMethod]
        public void Target_With_Attributes()
        {
            ThreadSafeFooWithAttributes foo = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Create<ThreadSafeFooWithAttributes>();

            AutoResetEvent thread1Enters = new AutoResetEvent(false);
            AutoResetEvent thread2Enters = new AutoResetEvent(false);
            AutoResetEvent thread1Finishes = new AutoResetEvent(false);
            AutoResetEvent thread2Finishes = new AutoResetEvent(false);

            ThreadPool.QueueUserWorkItem(delegate(object notUsed)
            {
                foo.Do(thread1Enters, thread1Finishes);
            });

            ThreadPool.QueueUserWorkItem(delegate(object notUsed)
            {
                foo.Do(thread2Enters, thread2Finishes);
            });

            Thread.Sleep(100); // Give time to both theads to try to enter.

            bool thread1Entered = thread1Enters.WaitOne(0, false);
            bool thread2Entered = thread2Enters.WaitOne(0, false);

            Assert.IsFalse(thread1Entered && thread2Entered, "Both threads entered the lock for the same SyncRoot");
        }
    }

    public class ThreadSafeFoo : MarshalByRefObject
    {
        public void Do(AutoResetEvent notify, WaitHandle exit)
        {
            notify.Set();
            exit.WaitOne();
        }
    }

    [ThreadSafeCallHandler("SyncRootB")]
    public class ThreadSafeFooWithAttributes : MarshalByRefObject
    {
        public void Do(AutoResetEvent notify, WaitHandle exit)
        {
            notify.Set();
            exit.WaitOne();
        }
    }
}

